home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FM Towns: Free Software Collection 7
/
FM Towns Free Software Collection 7.iso
/
ms_dos
/
thbgm
/
thbgm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-30
|
10KB
|
471 lines
/*
“THbgm”SNFファイル作成
By 五味
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
#define TRUE 1
#define FALSE 0
#define REST 0x80
#define TEMPO 0x90
#define CONTR 0xa0
#define VOLCH 0xb0
#define PITCH 0xc0
#define PANPO 0xd0
#define EOC 0x00
#define LOOP 0xff
#define MAXB 96*4
#define FBOCT 12
#define HEADERSIZE 256
#define PARTMAX 6
/* SNFフォーマット */
struct snfheader {
char name[4]; /* 識別子 */
char ver_high; /* バージョン上位 */
char ver_low; /* バージョン下位 */
char reserve1[2]; /* 予約域1 */
char title[56]; /* タイトル名 */
char fmbname[16]; /* FM音源ファイル名 */
char reserve2[16]; /* 予約域2 */
char applname[32]; /* 作成アプリ名 */
long dsize[PARTMAX]; /* パートのサイズ */
char reserve3[64-PARTMAX*4]; /* 予約域3 */
char reserve4[64]; /* 予約域4 */
} head;
FILE *part[PARTMAX]; /* パート毎のテンポラリ */
char *titlename=NULL; /* タイトル名 */
char *inputfile=NULL; /* ソースファイル名 */
char *outputfile=NULL; /* 生成ファイル名 */
char *fmbfile="fm_1.fmb"; /* FM音源ファイル名 */
char inputname[128]; /* ソースファィル名buf */
char outputname[128]; /* 生成ファイル名buf */
char fmbname[128]; /* FM音源ファイル名buf*/
int isloop=FALSE; /* ループさせるか */
int howpart=6; /* パート数 */
int line=1; /* 行番号 */
int block=1; /* ブロック数 */
int oct[PARTMAX]; /* オクターブ */
int gate[PARTMAX]; /* ゲートタイム */
int deflen[PARTMAX]; /* デフォルトの長さ */
int volume[PARTMAX]; /* ボリューム */
int all[PARTMAX]; /* 小節毎の長さ */
char vel[]={ 1, 8, 16, 24, 32, 40, 48, 56,
64, 72, 80, 88, 96,108,116,127 };
char *title= " 'THbgm' MML compiler\n"
" (c) H.Gomi 93/04/04\n";
char *usage= " [usage] THbgm <input_file> "
"[-fFMBname][-pPART][-l][-tTITLE][output_file]\n";
char *islpmes[]={ "NOLOOP","LOOP" };
char *parterror=" パート数の指定が違法です.\n";
char *lenpar=" %d: illegal length.\n";
char *velpar=" %d: ベロシティ設定が違法です(1~127)\n";
char *volpar=" %d: ボリューム設定が違法です(0~15)\n";
char *tempar=" %d: テンポ設定が違法です(40~280)\n";
char *octpar=" %d: オクターブ指定が違法です(0~8)\n";
char *dlnpar=" %d: 省略音長の指定が違法です(1~384)\n";
char *gtepar=" %d: ゲートタイムの指定が違法です(0~8)\n";
char *ocbpar=" %d: オクターブが下限を越えました\n";
char *ocupar=" %d: オクターブが上限を越えました\n";
char *cntpar=" %d: 音色変更の指定が違法です(1~128)\n";
char *pchpar=" %d: ピッチベンドの指定が違法です(-8192~8191)\n";
char *panpar=" %d: パンポッドの指定が違法です(-64~63)\n";
void makeheader(void)
{
FILE *fp;
int i;
char *buf;
if( (fp=fopen(outputfile,"wb"))==NULL ) {
printf(" can't creat outputfile'%s'.\n",outputfile);
exit(1);
}
memset(&head,'\0',HEADERSIZE);
strcpy(head.name,"SNF");
head.ver_high=1;
head.ver_low =0;
strcpy(head.fmbname,fmbfile);
for( i=0 ; i<howpart ; i++ )
head.dsize[i]=(long)ftell(part[i]);
strcpy(head.applname,"THbgm v1.0");
if( titlename ) strcpy(head.title,titlename);
else strcpy(head.title,"some piece");
fwrite(&head,HEADERSIZE,1,fp);
printf("----------<%s>----------\n",outputfile);
printf(" TITLE : %s\n",titlename);
printf(" FMBfile : %s\n",fmbfile);
printf(" SRCfile : %s\n",inputfile);
printf(" PART : %d\n",howpart);
printf(" BLOCK : %d\n",block);
printf(" LOOP : %s\n",islpmes[isloop]);
printf(" APPLICATION : %s\n",head.applname);
printf(" (SNF format v%d.%d)\n",head.ver_high,head.ver_low);
printf("------------------------------\n");
for( i=0 ; i<howpart ; i++ ) {
fseek(part[i],0,SEEK_SET);
if( (buf=malloc(head.dsize[i]))==NULL ) {
printf(" メモリが足りません.\n");
exit(1);
}
if( fread(buf,(size_t)head.dsize[i],1,part[i])==0 ||
fwrite(buf,(size_t)head.dsize[i],1,fp)==0 ) {
printf(" read & write failed.\n");
exit(1);
}
}
printf(" completed.\n");
exit(0);
}
char eget(FILE *fp) /* エラー処理付ストリーム入力 */
{
int ll;
if( (ll=fgetc(fp))==EOF ) {
if( ferror(fp) ) {
printf(" accident: file error.\n");
exit(2);
}else{
fclose(fp);
printf(" total %d blocks.\t\t\t\t\n",block);
makeheader();
}
}
return((char)ll);
}
void eunget(char c,FILE *fp) /* エラー処理付ungetc */
{
if( ungetc((int)c,fp)==EOF ) {
printf(" fatal: streem error.\n");
exit(3);
}
}
int egetnum(FILE *fp) /* ストリームから数値入力 */
{
int c,ll,sn;
if( (c=eget(fp))!='+' )
eunget(c,fp);
if( (c=eget(fp))=='-' )
sn=TRUE;
else{
sn=FALSE;
eunget(c,fp);
}
for( ll=0 ; ; ) {
c=eget(fp);
if( !isdigit(c) ) break;
ll=ll*10+(c-'0');
}
eunget(c,fp);
if( sn==TRUE ) return -ll;
else return ll;
}
void comerr(char *mes) /* エラーメッセージ表示と終了 */
{
printf(mes,line);
exit(1);
}
void makesnf(void) /* MMLコンパイラメイン */
{
FILE *fp;
int i;
char c;
int nowpart; /* 現在処理中のパート */
int code,rest,leap,len,key,val; /* 各種テンポラリ */
char tbuf[128]; /* 汎用buf */
if( (fp=fopen(inputfile,"r"))==NULL ) {
printf(" can't open'%s'.\n",inputfile);
exit(1);
}
for( i=0 ; i<howpart ; i++ ) {
if( (part[i]=tmpfile())==NULL ) {
printf(" creating temporary file failed.\n");
exit(1);
}
}
for( i=0 ; i<howpart ; i++ ) {
oct[i] = 4;
gate[i] = 7;
deflen[i]= 4;
volume[i]= vel[15];
all[i] = 0;
}
while(TRUE)
for( nowpart=0 ; nowpart<howpart ; ) {
code=0;rest=0;
switch(tolower(eget(fp))) {
case' ':
case'\t':
break;
case'/':
while( eget(fp)!='\n' );
line++;
break;
case'\n':
line++;
if( ++nowpart==howpart ) {
nowpart=0;
len=0;
for( i=0 ; i<howpart ; i++ )
if( len<all[i] )
len=all[i];
for( i=0 ; i<howpart ; i++ ) {
if( all[i]<len ) {
putc(REST,part[i]);
putw(len-all[i],part[i]);
}
}
for( i=0 ; i<howpart ; i++ )
all[i]=0;
sprintf(tbuf," %03d block done(step %d).%c",block++,len,0xd);
cputs(tbuf);
}
break;
case'v':
if( (c=eget(fp))=='@' ) {
val=egetnum(fp);
if( val<1 || 127<val )
comerr(velpar);
}else{
eunget(c,fp);
val=egetnum(fp);
if( val<0 || 15<val )
comerr(volpar);
val=vel[val];
}
volume[nowpart]=val;
putc(VOLCH, part[nowpart]);
putc((char)val, part[nowpart]);
break;
case't':
val=egetnum(fp);
if( val<40 || 280<val )
comerr(tempar);
putc(TEMPO, part[nowpart]);
putc((char)(val-30), part[nowpart]);
break;
case'o':
val=egetnum(fp);
if( val<0 || 8<val )
comerr(octpar);
oct[nowpart]=val;
break;
case'l':
val=egetnum(fp);
if( val<1 || MAXB<val )
comerr(dlnpar);
deflen[nowpart]=val;
break;
case'q':
val=egetnum(fp);
if( val<1 || 8<val )
comerr(gtepar);
gate[nowpart]=val;
break;
case'<':
if( --oct[nowpart]<0 )
comerr(ocbpar);
break;
case'>':
if( ++oct[nowpart]>8 )
comerr(ocupar);
break;
case'@':
val=egetnum(fp);
if( val<1 || 128<val )
comerr(cntpar);
putc(CONTR, part[nowpart]);
putc((char)(val-1), part[nowpart]);
break;
case'u':
val=egetnum(fp);
if( val<-8192 || 8191<val )
comerr(pchpar);
putc(PITCH, part[nowpart]);
putw(val, part[nowpart]);
break;
case'p':
val=egetnum(fp);
if( val<-64 || 63<val )
comerr(panpar);
putc(PANPO, part[nowpart]);
putc((char)(val+64), part[nowpart]);
break;
case'r':
rest=1;
case'b':
code++;
code++;
case'a':
code++;
code++;
case'g':
code++;
code++;
case'f':
code++;
case'e':
code++;
code++;
case'd':
code++;
code++;
case'c':
c=eget(fp);
if( c=='+' ) code++;
else if(c=='-') code--;
else eunget(c,fp);
leap=0;
do {
c=eget(fp);eunget(c,fp);
if( isdigit(c) ) {
len=egetnum(fp);
if( len<1 || MAXB<len )
comerr(lenpar);
}else len=deflen[nowpart];
leap=MAXB/len;
if( (c=eget(fp))=='.' ) leap+=(MAXB/2)/len;
else eunget(c,fp);
}while( (c=eget(fp))=='&' );
eunget(c,fp);
if( rest ) {
putc(REST,part[nowpart]);
putw(leap,part[nowpart]);
}else{
key=(leap*gate[nowpart])/8;
putc(code+oct[nowpart]*12+FBOCT,part[nowpart]);
putw(key, part[nowpart]);
if( key<leap ) {
putc(REST, part[nowpart]);
putw(leap-key, part[nowpart]);
}
}
all[nowpart]+=leap;
break;
default:
printf(" %d: illegal charactor'%c'.\n",line,c);
exit(1);
}
}
}
void main(int argc,char *argv[]) /* メイン */
{
int cm;
char *p;
printf(title);
for( cm=1 ; cm<argc ; cm++ ) {
if( *argv[cm]=='-' ) {
switch(*(argv[cm]+1)) {
case'h':
case'H':
case'?':
printf(usage);
exit(0);
case'f':
fmbfile=argv[cm]+2;
break;
case'l':
isloop=TRUE;
break;
case'p':
howpart=atoi(argv[cm]+2);
if( howpart<0 || howpart>PARTMAX ) {
printf(parterror);
exit(1);
}
break;
case't':
titlename=argv[cm]+2;
break;
default:
printf(" illegal option'%s'.\n",argv[cm]);
exit(1);
}
}else if( inputfile ==NULL ) {
inputfile =argv[cm];
}else if( outputfile==NULL ) {
outputfile=argv[cm];
}else {
printf(" too much file'%s'.\n",argv[cm]);
exit(1);
}
}
if( inputfile ==NULL ) {
printf(" no inputfile.\n");
exit(2);
}
if( strchr(inputfile,'.')==NULL ) {
strcpy(inputname,inputfile);
strcat(inputname,".mml");
inputfile=inputname;
}
if( outputfile==NULL ) {
strcpy(outputname,inputfile);
outputfile=outputname;
if( (p=strchr(outputfile,'.'))==NULL ) {
strcat(outputfile,".snf");
}else{
strcpy(p,".snf");
}
}
if( strchr(fmbfile,'.')==NULL ) {
strcpy(fmbname,fmbfile);
strcat(fmbname,".fmb");
fmbfile=fmbname;
}
makesnf();
}